﻿using Mogre;
using System;

namespace MogreSample
{
    class TerrainCamera : IDisposable
    {
        SceneNode baseNode, pivotNode, camNode;
        Camera camera;
        RaySceneQuery rayQuery;
        float height;

        public Camera Camera
        {
            get { return camera; }
        }

        public TerrainCamera(SceneNode baseNode, Camera camera)
            : this(baseNode, camera, new Vector3(0, 40, -60), 20)
        {
        }

        public TerrainCamera(SceneNode baseNode, Camera camera, Vector3 offset, float height)
        {
            this.baseNode = baseNode;
            this.camera = camera;
            this.height = height;

            pivotNode = baseNode.CreateChildSceneNode(baseNode.Name + "_PivotNode", new Vector3(700, 300, 700));
            camNode = pivotNode.CreateChildSceneNode(baseNode.Name + "_CameraNode", offset);
            camNode.Yaw(new Degree(180));
            camNode.AttachObject(camera);
            rayQuery = camera.SceneManager.CreateRayQuery(new Ray(pivotNode.Position, Vector3.NEGATIVE_UNIT_Y));
            ClampToTerrain();
        }

        public void Dispose()
        {
            camNode.DetachAllObjects();
            baseNode.RemoveAndDestroyChild(pivotNode.Name);

            GC.SuppressFinalize(this);
        }

        public void Spin(Radian angle)
        {
            pivotNode.Yaw(angle);
        }

        public void Pitch(Radian angle)
        {
            pivotNode.Pitch(angle);
        }

        public void Translate(Vector3 displacement)
        {
            pivotNode.Translate(displacement, Node.TransformSpace.TS_LOCAL);
        }

        public void ClampToTerrain()
        {
	        rayQuery.Ray = new Ray(pivotNode.Position + new Vector3(0, 200, 0), Vector3.NEGATIVE_UNIT_Y);
	        RaySceneQueryResult qryResult = rayQuery.Execute();
	        RaySceneQueryResult.Iterator i = qryResult.Begin();
	        if(i != qryResult.End() && i.Value.worldFragment != null)
		        pivotNode.SetPosition(pivotNode.Position.x, i.Value.worldFragment.singleIntersection.y + 1 + height, pivotNode.Position.z);
        }

        public void OrientPlaneToCamera(SceneNode planeNode, int planeHeight)
        {
	        pivotNode.Translate(new Vector3(0, 0, 270), Node.TransformSpace.TS_LOCAL);

	        planeNode.Position = pivotNode.Position;
        	
	        pivotNode.Translate(new Vector3(0, 0, -270), Node.TransformSpace.TS_LOCAL);

	        planeNode.Orientation = pivotNode.Orientation;
	        planeNode.Yaw(new Degree(90));

	        rayQuery.Ray = new Ray(planeNode.Position + new Vector3(0, 170, 0), Vector3.NEGATIVE_UNIT_Y);
	        RaySceneQueryResult qryResult = rayQuery.Execute();
	        RaySceneQueryResult.Iterator i = qryResult.Begin();
	        if(i != qryResult.End() && i.Value.worldFragment != null)
		        planeNode.SetPosition(planeNode.Position.x, i.Value.worldFragment.singleIntersection.y + planeHeight / 2, planeNode.Position.z);
        }
    };
}
